package com.kfm.service.impl;

import com.kfm.service.IUserService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
public class UserServiceImpl implements IUserService {

    /**
     *  Security 鉴权 Service 中的 loadUserByUsername 方法，
     *  会在需要鉴权时（比如 登录） 将输入的 username 传入此方法
     * @param username 用户输入的 username
     * @return 鉴权对象，一般为 输入 username 对应的用户信息，此用户信息需要是 实现了 UserDetails 的类的对象，
     *         返回的对象应该包含 密码，会将此对象的密码和用户输入的密码进行比对，并判断 状态信息（如 是否锁定，过期等）
     *         都通过则鉴权成功。
     * @throws UsernameNotFoundException 如果传递的用户名不存在则应该抛出此异常
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        /**
         * 此处模拟数据库操作，模拟数据库中只有两个 username为 admin 和 user 的用户
         *  如果输入的 username 不是 admin 或者 user 的话就 throw UsernameNotFoundException 异常
         */
        if (!"admin".equals(username) || "user".equals(username)){
            throw new UsernameNotFoundException("用户名不存在");
        }

        /*
         这里我们模拟数据库查询到 username 对应的信息，然后直接设置 角色/权限 到 List
            角色：ROLE_ADMIN  （管理员）
                 ROLE_USER   （普通用户）
            权限： USER:ADD  添加用户
                  USER:EDIT 修改用户
         */
        // 设置 授权信息
        List<String> list = List.of("ROLE_ADMIN", "ROLE_USER", "USER:ADD", "USER:EDIT");
        Set<GrantedAuthority> roles = new HashSet<>();
        for (String role : list){
            roles.add(new SimpleGrantedAuthority(role));
        }
        /*
         使用 Security 中提供的 User 类， 此类实现了 UserDetails 接口
            使用 User(String username, String password, Collection<? extends GrantedAuthority> authorities) 构造
              第一个参数表示 用户名
              第二个参数表示 密码 （应该由数据库中查出， 密码字符串中应该是使用了 Security 密码策略加密后的. 例如：{noop}admin ）
              第三个参数表示 用户的授权信息，一般为一个 Set 集合
         */
        // {noop}123456 表示使用 NoOpPasswordEncoder 加密后的密码, 用户输入时输入 {noop} 后面的内容即可匹配
        User user = new User(username, "{noop}123456", roles);
        return user;
    }


}
